#pragma once

#include <string>
#include <functional>
#include <cstring>
#include <fstream>

#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#include <pthread.h>

#include "protocol.hpp"

namespace Server
{
    enum
    {
        USAGE_ERROR = 1,
        SOCKET_ERROR,
        BIND_ERROR,
        LISTEN_ERROR,
        OPEN_ERROR
    };

    using func_t = std::function<bool(const httpRequest&, httpResponse&)>;

    const uint16_t gport = 8080;
    const int gnacklog = 5;

    

    class httpServer
    {
    public:
        httpServer(func_t func, uint16_t port = gport)
            : _sock_listen(0), _port(port), _func(func)
        {}

        void init()
        {
            // 1. 创建socket
            _sock_listen = socket(AF_INET, SOCK_STREAM, 0);
            if (_sock_listen == -1)
            {
                exit(SOCKET_ERROR);
            }

            // 2. bind 端口
            struct sockaddr_in local;
            memset(&local, 0, sizeof(local));
            local.sin_family = AF_INET;
            local.sin_port = htons(_port);
            local.sin_addr.s_addr = INADDR_ANY;

            if (bind(_sock_listen, (const struct sockaddr*)&local, sizeof(local)) < 0)
            {
                exit(BIND_ERROR);
            }

            // 3. 设置socket 为 listen 状态
            if (listen(_sock_listen, gnacklog) < 0)
            {
                exit(LISTEN_ERROR);
            }
        }

        void start()
        {
            signal(SIGCHLD, SIG_IGN);
            while (true)
            {
                // 4. 获取新连接
                struct sockaddr_in client;
                memset(&client, 0, sizeof(client));
                socklen_t clientlen = sizeof(client);
                int sockfd = accept(_sock_listen, (struct sockaddr *)&client, &clientlen);
                if (sockfd < 0)
                {
                    continue;
                }
                std::cout << "sock: " << sockfd << std::endl;

                // 多进程版本
                pid_t id = fork();
                if (id == 0)
                {
                    close(_sock_listen);
#ifdef DEBUG
                    std::cout << "创建子进程" << std::endl;
#endif
                    // TODO
                    httpHander(sockfd);
                    close(sockfd);
                    exit(0);
                }
                close(sockfd);
            }
        }

    private:
        void httpHander(int sockfd)
        {
            // 读请求
            // request反序列化
            // 操作
            // respond序列化
            // send
            char buffer[4096];
            httpRequest req;
            httpResponse resp;
            ssize_t n = recv(sockfd, buffer, sizeof(buffer) - 1, 0);
            if (n > 0)
            {
                buffer[n] = 0;
                req.inbuffer = buffer;
                req.paser();
                _func(req, resp);

                send(sockfd, resp.outbuffer.c_str(), resp.outbuffer.size(), 0);
            }
        }

    private:
        int _sock_listen;
        uint16_t _port;
        func_t _func;
    };
}

